#include "ListWidgetShell.h"
#include "../../Utils/XXlogger.h"

ListWidgetShell::ListWidgetShell(QObject *parent) : QObject(parent)
{
    _listWidget = nullptr;
    _currentSelectCell = nullptr;
    _currentActiveCell = nullptr;
}

void ListWidgetShell::shell(QListWidget *listWidget){
    if(_listWidget){
        xxErr("could not reset listWidget that is not nullptr.");
        return;
    }
    _listWidget = listWidget;
    connect(_listWidget,&QListWidget::itemClicked,this,&ListWidgetShell::listWidget_onItemClicked);
}

// config
void ListWidgetShell::configRow(QMetaObject cls, QSize size){
    _cls = cls;
    _rowSize = size;
}
void ListWidgetShell::configDblSelectable(bool selectable){
    if(selectable){
        connect(_listWidget,&QListWidget::itemDoubleClicked,this,&ListWidgetShell::listWidget_onItemDoubleClicked);
    }
    else {
        disconnect(_listWidget,&QListWidget::itemDoubleClicked,this,&ListWidgetShell::listWidget_onItemDoubleClicked);
    }
}

// action
void ListWidgetShell::appendData(const QVariant &data){
    QListWidgetItem *item = nullptr;
    CellBase *cell = nullptr;
    makeItemCell(&item,&cell,data);
    _listWidget->addItem(item);
    _listWidget->setItemWidget(item,cell);
    _cells.append(cell);
}
void ListWidgetShell::insertData(int row, const QVariant &data){
    QListWidgetItem *item = nullptr;
    CellBase *cell = nullptr;
    makeItemCell(&item,&cell,data);
    _listWidget->insertItem(row,item);
    _listWidget->setItemWidget(item,cell);
    _cells.insert(row,cell);
}
void ListWidgetShell::removeData(int row){
    if(row>=_listWidget->count() || row<0){
        xxErr("invalid row. available count of listWidget:%d row:%d",_listWidget->count(), row);
        return;
    }

    QListWidgetItem *item = _listWidget->takeItem(row);
    CellBase *cell = _cells.takeAt(row);
    delete cell;
    delete item;
}
QVariantList ListWidgetShell::getData(){
    QVariantList datas;
    for (int index=0; index<_cells.count(); index++) {
        datas.append(_cells.value(index)->getData());
    }
    return datas;
}
QVariant ListWidgetShell::getData(int row){
    if(row>=_listWidget->count() || row<0){
        xxErr("invalid row. available count of listWidget:%d row:%d",_listWidget->count(), row);
        return QVariant();
    }
    if(row>=_cells.count() || row<0){
        xxErr("invalid row. available count of cell:%d row:%d",_listWidget->count(), row);
        return QVariant();
    }
    return _cells.value(row)->getData();
}
QVariant ListWidgetShell::takeData(int row){
    if(row>=_listWidget->count() || row<0){
        xxErr("invalid row. available count of listWidget:%d row:%d",_listWidget->count(), row);
        return QVariant();
    }
    if(row>=_cells.count() || row<0){
        xxErr("invalid row. available count of cell:%d row:%d",_listWidget->count(), row);
        return QVariant();
    }
    CellBase *cell = _cells.takeAt(row);
    QVariant data = cell->getData();
    delete cell;
    delete _listWidget->takeItem(row);
    return data;
}

void ListWidgetShell::setData(const QVariantList &datas){
    for (int row=0; row<datas.count(); row++) {
        if(row<_cells.count()){
            _cells.value(row)->setData(datas[row]);
        }
        else{
            appendData(datas.value(row));
        }
    }
    while(_cells.count()>datas.count()){
        delete _cells.takeLast();
        delete _listWidget->takeItem(_listWidget->count()-1);
    }
}
void ListWidgetShell::setData(int row, const QVariant &data){
    if(row>=_listWidget->count() || row<0){
        xxErr("invalid row. available count of listWidget:%d row:%d",_listWidget->count(), row);
        return;
    }
    if(row>=_cells.count() || row<0){
        xxErr("invalid row. available count of cell:%d row:%d",_listWidget->count(), row);
        return;
    }
    _cells.value(row)->setData(data);
}
void ListWidgetShell::updateData(int row, const QVariant &data){
    if(row>=_listWidget->count() || row<0){
        xxErr("invalid row. available count of listWidget:%d row:%d",_listWidget->count(), row);
        return;
    }
    if(row>=_cells.count() || row<0){
        xxErr("invalid row. available count of cell:%d row:%d",_listWidget->count(), row);
        return;
    }
    _cells.value(row)->updateData(data);
}
void ListWidgetShell::select(int row){
    setCurrentSelect(_cells.value(row,nullptr));
}
int ListWidgetShell::findRowEqualTo(const QVariant &data){
    for (int row=0; row<_cells.count(); row++) {
        QVariant cellData = _cells.value(row)->getData();
        bool matching = true;
        if(cellData.canConvert<QVariantMap>() && data.canConvert<QVariantMap>()){
            QVariantMap cellDataMap = cellData.toMap();
            QVariantMap dataMap = data.toMap();
            for (auto iter=dataMap.begin(); iter!=dataMap.end(); iter++) {
                if(!cellDataMap.contains(iter.key()) || cellDataMap.value(iter.key()) != iter.value()){
                    matching = false;
                    break;
                }
            }
        }
        else if(cellData.canConvert<QString>() && data.canConvert<QString>()){
            matching = cellData.toString()==data.toString();
        }
        else{
           matching=false;
        }

        if(matching){
           return row;
        }
    }
    return -1;
}

// private
void ListWidgetShell::setCurrentActive(CellBase *cell){
    if(cell == _currentActiveCell){
        return;
    }
    if(_currentActiveCell){
        _currentActiveCell->setActived(false);
        disconnect(_currentActiveCell,&QObject::destroyed,this,&ListWidgetShell::xcell_onDestroyed);
    }
    if(cell){
        cell->setActived(true);
        connect(cell,&QObject::destroyed,this,&ListWidgetShell::xcell_onDestroyed);
    }
    _currentActiveCell = cell;
}
void ListWidgetShell::setCurrentSelect(CellBase *cell){
    if(cell == _currentSelectCell){
        return;
    }
    if(_currentSelectCell){
        _currentSelectCell->setSelected(false);
        disconnect(_currentSelectCell,&QObject::destroyed,this,&ListWidgetShell::xcell_onDestroyed);
    }
    if(cell){
        cell->setSelected(true);
        connect(cell,&QObject::destroyed,this,&ListWidgetShell::xcell_onDestroyed);
    }
    int previous = _currentSelectCell?_cells.indexOf(_currentSelectCell):-1;
    int current = cell?_cells.indexOf(cell):-1;
    _currentSelectCell = cell;
    emit sigSelectionChanged(current,previous);

}
void ListWidgetShell::makeItemCell(QListWidgetItem **item, CellBase **cell, QVariant data){
    *item = new QListWidgetItem;
    (*item)->setSizeHint(_rowSize);
    QObject *obj = _cls.newInstance();
    *cell = qobject_cast<CellBase*>(obj);
    (*cell)->setParent(_listWidget);
    (*cell)->setData(data);
    connect(*cell,&CellBase::sigEvent,this,&ListWidgetShell::xcell_onEvent);
    connect(*cell,&CellBase::sigDataChanged,this,&ListWidgetShell::xcell_onDataChanged);
}

// slots
void ListWidgetShell::listWidget_onItemClicked(QListWidgetItem *item){
    int row = _listWidget->row(item);
    CellBase *cell = _cells.value(row);
    setCurrentActive(cell);
}
void ListWidgetShell::listWidget_onItemDoubleClicked(QListWidgetItem *item){
    int row = _listWidget->row(item);
    CellBase *cell = _cells.value(row);
    setCurrentSelect(cell);
}
void ListWidgetShell::xcell_onEvent(QString name, QVariant info){
    CellBase *cell = qobject_cast<CellBase*>(sender());
    int row = _cells.indexOf(cell);
    emit sigEvent(row,name,info);
}
void ListWidgetShell::xcell_onDataChanged(){
    CellBase *cell = qobject_cast<CellBase*>(sender());
    int row = _cells.indexOf(cell);
    emit sigDataChanged(row);
}
void ListWidgetShell::xcell_onDestroyed(QObject *object){
    if(object == _currentActiveCell){
        setCurrentActive(nullptr);
    }
    if(object == _currentSelectCell){
        setCurrentSelect(nullptr);
    }
}
